package cn.jn.lhm.netty.part05;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import lombok.val;

import java.nio.charset.StandardCharsets;

/**
 * @author lhm 2753914576@qq.com
 * @time 2023/7/12 - 23:10
 **/
@Slf4j
@SuppressWarnings("all")
public class Server {

    public static void main(String[] args) {
        new ServerBootstrap()
                .group(new NioEventLoopGroup(), new NioEventLoopGroup(2))
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    // 默认自带 head ， tail 两个 Handler
                    // head -> tail
                    @Override
                    protected void initChannel(NioSocketChannel client) throws Exception {
                        ChannelPipeline pipeline = client.pipeline();

                        //  添加入栈处理器
                        addInBoundHandler(client, pipeline);

                        // 添加出栈处理器
                        addOutBoundHandler(pipeline);
                    }

                    private void addOutBoundHandler(ChannelPipeline pipeline) {
                        pipeline.addLast("h4", new ChannelOutboundHandlerAdapter() {
                            @Override
                            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
                                log.info("4");
                                super.write(ctx, msg, promise);
                            }
                        });
                        pipeline.addLast("h5", new ChannelOutboundHandlerAdapter() {
                            @Override
                            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
                                log.info("5");
                                super.write(ctx, msg, promise);
                            }
                        });
                        pipeline.addLast("h6", new ChannelOutboundHandlerAdapter() {
                            @Override
                            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
                                log.info("6");
                                super.write(ctx, msg, promise);
                            }
                        });
                    }

                    private void addInBoundHandler(NioSocketChannel client, ChannelPipeline pipeline) {
                        pipeline.addLast("h1", new ChannelInboundHandlerAdapter() {
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                log.info("1");
                                super.channelRead(ctx, msg);
                            }
                        });
                        pipeline.addLast("h2", new ChannelInboundHandlerAdapter() {
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                log.info("2");
                                super.channelRead(ctx, msg);
                            }
                        });
                        pipeline.addLast("h3", new ChannelInboundHandlerAdapter() {
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                log.info("3");
                                // 发送消息触发出栈处理器
                                super.channelRead(ctx, msg);
                                val data = ctx.alloc().buffer().writeBytes("server...".getBytes(StandardCharsets.UTF_8));
                                // 会从 tail位置开始触发调用出栈处理器
                                // client.writeAndFlush(data);

                                // 会从当前处理器位置开始触发，往前找入栈处理器
                                ctx.writeAndFlush(data);
                            }
                        });
                    }
                })
                .bind(8080);
    }
}
